#pragma once
#include "../common/net.hpp"
#include <set>
namespace qiangsir
{
    namespace server
    {
        class ProviderMananger
        {
        public:
            using ptr = std::shared_ptr<ProviderMananger>;
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex mutex;
                Address host; // 服务提供者的主机
                std::vector<std::string> methods;
                BaseConnection::ptr conn;
                Provider(const BaseConnection::ptr &c, const Address &h) 
                : conn(c), host(h){}
                void appdMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    methods.push_back(method);
                }
            };
            void addProvider(const BaseConnection::ptr &conn, const Address &addr, const std::string &method)
            {
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it != _conns.end())
                    {
                        provider = it->second;
                    }
                    else
                    {
                        provider = std::make_shared<Provider>(conn, addr);
                        _conns.insert(std::make_pair(conn, provider));
                    }
                    // 向providers添加数据
                    auto &providers = _providers[method];
                    providers.insert(provider);
                }
                // 向provider对象的methods加入新的业务
                provider->appdMethod(method);
            }
            Provider::ptr getProvider(const BaseConnection::ptr &conn)
            {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it != _conns.end())
                    {
                        return it->second;
                    }
                  return Provider::ptr();
            }
            void delProvider(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                {
                    return;
                }
                // 找到提供者的业务，并一一移除,通过业务找到该提供者移除
                for (auto &method : it->second->methods)
                {
                    auto &providers = _providers[method];
                    providers.erase(it->second);
                }
                _conns.erase(it);
            }
            std::vector<Address> methodhosts(const std::string &method)
            {
                auto it = _providers.find(method);
                if (it == _providers.end())
                {
                    // 无该服务的注册者
                    return std::vector<Address>();
                }
                std::vector<Address> result;
                for (auto &provider : it->second)
                {
                    result.push_back(provider->host);
                }
                return result;
            }

        private:
            std::mutex _mutex;
            //<service>------>>{provider1,provider2...}
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
        };

        class DiscoverMananger
        {
        public:
            using ptr = std::shared_ptr<DiscoverMananger>;
            struct Discover
            {
                using ptr = std::shared_ptr<Discover>;
                std::mutex mutex;
                BaseConnection::ptr conn;
                std::vector<std::string> methods;
                Discover(const BaseConnection::ptr &c) : conn(c) {}
                void appdMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(mutex);
                    methods.push_back(method);
                }
            };
            void addDiscover(const BaseConnection::ptr &conn, const std::string &method)
            {
                Discover::ptr discover;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it != _conns.end())
                    {
                        discover = it->second;
                    }
                    else
                    {
                        discover = std::make_shared<Discover>(conn);
                        _conns.insert(std::make_pair(conn, discover));
                    }
                    auto &discovers = _discovers[method];
                    discovers.insert(discover);
                }
                discover->appdMethod(method);
            }
            void delDiscover(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                {
                    return;
                }
                // 找到发现者的业务，并一一移除,通过业务找到发现者移除
                for (auto &method : it->second->methods)
                {
                    auto &discovers = _discovers[method];
                    discovers.erase(it->second);
                }
                _conns.erase(it);
            }
            void onlineNotify(const std::string &method, const Address &host)
            {
                return notify(method, host, ServiceOptype::SERVICE_ONLINE);
            }
            void offlineNotify(const std::string &method, const Address &host)
            {
                return notify(method, host, ServiceOptype::SERVICE_OFFLINE);
            }

        private:
            void notify(const std::string &method, const Address &host, ServiceOptype optype)
            {
                // 查询链接
                std::unique_lock<std::mutex> lock(_mutex);
                auto discovers = _discovers.find(method);
                if (discovers == _discovers.end())
                {
                    // 代表该服务没有发现者
                    return;
                }

                ServiceRequest::ptr msg_req = BaseMessageFactory::create<ServiceRequest>();
                msg_req->setHost(host);
                msg_req->setType(MType::REQ_SERVERICE);
                msg_req->setId(UUID::uuid());
                msg_req->setMethod(method);
                msg_req->setOptype(optype);

                for (auto &discover : discovers->second)
                {
                    discover->conn->send(msg_req);
                }
            }
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Discover::ptr>> _discovers;
            std::unordered_map<BaseConnection::ptr, Discover::ptr> _conns;
        };
        class PDMananger
        {
        public:
            using ptr = std::shared_ptr<PDMananger>;
            PDMananger() : _providermanager(std::make_shared<ProviderMananger>()),
                           _discovermanager(std::make_shared<DiscoverMananger>())
            {
            }
            void onServiceRequest(const BaseConnection::ptr &conn, ServiceRequest::ptr &msg)
            {
                // 服务注册、服务发现
                ServiceOptype optype;
                if (msg->optype() == ServiceOptype::SERVICE_REGISTRY)
                {
                    // 1.新增提供者
                    _providermanager->addProvider(conn, msg->host(), msg->method());
                    // 2.上线
                    _discovermanager->onlineNotify(msg->method(), msg->host());
                    // 注册应答
                    return registerResponse(conn, msg);
                }
                else if (msg->optype() == ServiceOptype::SERVICE_DISCOVERY)
                {
                    // 1.服务发现
                    _discovermanager->addDiscover(conn, msg->method());
                    return discoverResponse(conn, msg);
                }
                else
                {
                    ELOG("未知服务请求");
                    return errorResponse(conn,msg);
                }
            }
            void onConnectionRequest(const BaseConnection::ptr &conn)
            {
                //断开连接时，进行服务下下线
                auto provider = _providermanager->getProvider(conn);
                if (provider.get() != nullptr)
                {
                    for (auto method : provider->methods)
                    {
                        _discovermanager->offlineNotify(method, provider->host);
                    }
                    _providermanager->delProvider(conn);
                }
                _discovermanager->delDiscover(conn);
            }

        private:
            void registerResponse(const BaseConnection::ptr &conn, ServiceRequest::ptr &msg)
            {
                ServiceResponse::ptr msg_rsp = BaseMessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->id());
                msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY);
                msg_rsp->setType(MType::RSP_SERVERICE);
                msg_rsp->setRcode(RCode::RCODE_OK);
                conn->send(msg_rsp);
            }
            void discoverResponse(const BaseConnection::ptr &conn, ServiceRequest::ptr &msg)
            {
                ServiceResponse::ptr msg_rsp = BaseMessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->id());
                msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVERY);
                msg_rsp->setType(MType::RSP_SERVERICE);

                std::vector<Address> hosts = _providermanager->methodhosts(msg->method());
                if (hosts.empty())
                {
                    msg_rsp->setRcode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->send(msg_rsp);
                }
                msg_rsp->setRcode(RCode::RCODE_OK);
                msg_rsp->setMethod(msg->method());
                msg_rsp->setHost(hosts);
                return conn->send(msg_rsp);
            }
            void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                auto msg_rsp = BaseMessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->id());
                msg_rsp->setType(MType::RSP_SERVERICE);
                msg_rsp->setRcode(RCode::RCODE_INVALID_OPTYPE);
                msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW);
                conn->send(msg_rsp);
            }

        private:
            ProviderMananger::ptr _providermanager;
            DiscoverMananger::ptr _discovermanager;
        };
    }
}